package com.eqxiu.ieditor.api.impl.order;

import java.net.URLEncoder;

import com.eqxiu.ieditor.api.impl.HomePageSceneServiceApiImpl;
import com.eqxiu.ieditor.api.order.IOrderServiceApi;
import com.eqxiu.ieditor.commons.crypt.MD5Util;
import com.eqxiu.ieditor.dao.OrderItemMapper;
import com.eqxiu.ieditor.dao.OrderMapper;
import com.eqxiu.ieditor.dto.ItemDTO;
import com.eqxiu.ieditor.dto.OrderDTO;
import com.eqxiu.ieditor.dto.OrderStatusEnum;
import com.eqxiu.ieditor.dto.OrderTypeEnum;
import com.eqxiu.ieditor.entity.Order;
import com.eqxiu.ieditor.entity.OrderExample;
import com.eqxiu.ieditor.entity.OrderItem;
import com.eqxiu.user.api.UserApi;
import com.eqxiu.user.api.dto.User;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @description 订单的实现类
 * @author ranger
 * @update lifen
 * @date May 26, 2017
 */
@Component
public class OrderServiceApiImpl implements IOrderServiceApi {
	
    private final Logger LOGGER = LoggerFactory.getLogger(OrderServiceApiImpl.class);

    
	@Autowired
	private OrderMapper orderMapper;

	@Autowired
	private OrderItemMapper orderItemMapper;

	@Autowired
    private UserApi userApi;

	@Override
	public String signParam(Map<String, Object> param,String appKey) {
		SortedMap<String, Object> smap = new TreeMap<String, Object>(param);
		StringBuffer stringBuffer = new StringBuffer();
		for (Map.Entry<String, Object> m : smap.entrySet()) {
			Object value = m.getValue();
			if (value != null && !"".equals(String.valueOf(value))) {
				try {
					stringBuffer.append(m.getKey()).append("=").append(URLEncoder.encode(String.valueOf(value), "UTF-8")).append("&");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}
		}
		stringBuffer.delete(stringBuffer.length() - 1, stringBuffer.length());
		String argPreSign = stringBuffer.append("&payKey=").append(appKey).toString();
		LOGGER.error("待签名在订单=="+argPreSign);
		String signStr = MD5Util.encode(argPreSign).toUpperCase();

		return signStr;
	}

	@Override
	@Transactional(readOnly = false)
	public OrderDTO createOrder(OrderDTO orderDTO) {
		Order order = new Order();
		BeanUtils.copyProperties(orderDTO, order);
		order.setStatus(OrderStatusEnum.NEW.status());
		order.setCreateTime(new Date());
		orderMapper.insert(order);
		orderDTO.setId(order.getId());
		List<ItemDTO> items = orderDTO.getItems();
		if (items != null) {
			for (ItemDTO dto : items) {
				OrderItem item = new OrderItem();
				BeanUtils.copyProperties(dto, item);
				item.setCode(order.getProductCode());
				item.setOrderId(order.getId());
				item.setCreateTime(new Date());
				orderItemMapper.insertSelective(item);
			}
		}
		return orderDTO;
	}

	@Override
	public OrderDTO selectByPrimaryKey(Long id) {
		Order order = orderMapper.selectByPrimaryKey(id);
		OrderDTO dto = new OrderDTO();
		if (Objects.nonNull(order)) {
			BeanUtils.copyProperties(order, dto);
		}
		return dto;
	}

	@Override
	public List<OrderDTO> selectByOrderId(Long orderId,String userId) {
		OrderExample example = new OrderExample();
		example.createCriteria().andIdEqualTo(orderId).andCreateUserEqualTo(userId);
		return getOrderDTOS(example);
	}

	@Override
	public List<OrderDTO> selectByCode(String code,String userId) {
		OrderExample example = new OrderExample();
		example.createCriteria().andCodeEqualTo(code).andCreateUserEqualTo(userId)
				.andStatusEqualTo(OrderStatusEnum.PAID.status()).andPayTypeEqualTo(OrderTypeEnum.COST.getState());
		return getOrderDTOS(example);
	}

	private List<OrderDTO> getOrderDTOS(OrderExample example) {
		List<Order> orders = orderMapper.selectByExample(example);
		List<OrderDTO> dtos = Lists.newArrayList();
		if (Objects.nonNull(orders) && orders.size() > 0) {
			for (Order order:orders){
				OrderDTO dto = new OrderDTO();
				BeanUtils.copyProperties(order, dto);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@Override
	public OrderDTO findOrder(String orderSn) {
		OrderExample example = new OrderExample();
		example.createCriteria().andOutOrderIdEqualTo(orderSn);
		List<Order> orders = orderMapper.selectByExample(example);
		OrderDTO dto = new OrderDTO();
		if (orders != null && orders.size() > 0) {
			BeanUtils.copyProperties(orders.get(0), dto);
		}
		return dto;
	}

	@Override
	@Transactional(readOnly = false)
	public int finishOrder(OrderDTO dto) {
		Order order = new Order();
		BeanUtils.copyProperties(dto, order);
		return orderMapper.updateByPrimaryKeySelective(order);
	}

	@Override
	public List<OrderDTO> selectByIdAndPayType(Long id,String userId) {
	   OrderExample example = new OrderExample();
		example.createCriteria().andIdEqualTo(Long.valueOf(id)).andCreateUserEqualTo(userId)
				.andPayTypeEqualTo(OrderTypeEnum .COST.getState()).andStatusEqualTo(OrderStatusEnum.NEW.status());
		return getOrderDTOS(example);
	}

	@Override
	public List<OrderDTO> selectByIdAndUserId(Long id,String userId) {
		OrderExample example = new OrderExample();
		example.createCriteria().andIdEqualTo(Long.valueOf(id)).andCreateUserEqualTo(userId);
		return getOrderDTOS(example);
	}

	@Override
	public List<OrderDTO> selectByIdAndCode(Long id,String userId,String code,Long prodId) {
		OrderExample example = new OrderExample();
		OrderExample.Criteria criteria = example.createCriteria().andIdEqualTo(id)
				.andCreateUserEqualTo(userId).andStatusEqualTo(OrderStatusEnum.NEW.status());
		addCriteria(code, prodId, criteria);
		return getOrderDTOS(example);
	}
	@Override
	public List<OrderDTO> findByCondition(OrderDTO orderDTO) {
		OrderExample example=new OrderExample();
		OrderExample.Criteria criteria=example.createCriteria();
		if (orderDTO.getId()!=null){
			criteria.andIdEqualTo(orderDTO.getId());
		}
		if (orderDTO.getCreateUser()!=null){
			criteria.andCreateUserEqualTo(orderDTO.getCreateUser());
		}
		if (orderDTO.getStatus()!=null){
			criteria.andStatusEqualTo(orderDTO.getStatus());
		}
		if (orderDTO.getPayType()!=null){
			criteria.andPayTypeEqualTo(orderDTO.getPayType());
		}

		if (orderDTO.getCode()!=null){
			criteria.andCodeEqualTo(orderDTO.getCode());
		}
		if (orderDTO.getProductId()!=null){
			criteria.andProductIdEqualTo(orderDTO.getProductId());
		}
		return getOrderDTOS(example);
	}

	private void addCriteria(String code, Long prodId, OrderExample.Criteria criteria) {
		if (code != null) {
			criteria.andCodeEqualTo(code);
		}
		if (prodId != null) {
			criteria.andProductIdEqualTo(prodId.intValue());
		}
	}

    @Override
    public OrderDTO findOrder(Long id) {
        Order order = orderMapper.selectByPrimaryKey(id);
        OrderDTO dto = new OrderDTO();
        BeanUtils.copyProperties(order, dto);
        return dto;
    }

    @Override
    public int deleteByID(Long id) {
        return orderMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int updateByID(OrderDTO dto) {
        Order order = new Order();
        BeanUtils.copyProperties(dto, order);
        return orderMapper.updateByPrimaryKeySelective(order);
    }

    @Override
    public List<OrderDTO> findByTime(String startTime, String endTime) {
        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andCreateTimeBetween(startTime, endTime).andStatusEqualTo(Byte.parseByte("1"));
        List<Order> orders = orderMapper.selectByExample(orderExample);
        List<OrderDTO> orderDTOs = new ArrayList<>();
        orders.forEach(
                one -> {
                    OrderDTO dto = new OrderDTO();
                    BeanUtils.copyProperties(one, dto);
                    orderDTOs.add(dto);
                }
        );
        return orderDTOs;

    }

    @Override
    public Map<String, Object> findByParams(Map<String, String> params) {
        Integer pageNumber = Integer.parseInt(params.get("pageNumber"));
        Integer pageSize = Integer.parseInt(params.get("pageSize"));
        OrderExample example = setParams(params);
        example.setOrderByClause("create_time desc");
        Page<Order> orderPage = PageHelper.startPage(pageNumber, pageSize).doSelectPage(
                () -> {
                    orderMapper.selectByExample(example);
                }
        );
        List<Order> orders = orderPage.getResult();

        List<OrderDTO> orderDTOs = orders.stream().map(
                one -> {
                    OrderDTO dto = new OrderDTO();
                    BeanUtils.copyProperties(one, dto);
                    String createUser = one.getCreateUser();
                    if (createUser != null) {
                        dto.setLoginName(userApi.getLoginName(createUser));
                    }
                    return dto;
                }
        ).collect(Collectors.toList());

        Map<String, Object> map = Maps.newHashMap();
        map.put("total", orderPage.getTotal());
        map.put("rows", orderDTOs);

        return map;
    }

    /**
     * @description //TODO 设计说明
     * @author ranger
     * @date Jun 8, 2017
     * @modified by xxx 修改说明
     * @param createStartTime
     * @param createEndTime
     * @param criteria
     */
    private void addTimeRange(String createStartTime, String createEndTime, OrderExample.Criteria criteria) {
        if (StringUtils.isNoneBlank(createStartTime) && StringUtils.isNoneBlank(createEndTime)) {
            criteria.andCreateTimeBetween(createStartTime, createEndTime);
        } else if (StringUtils.isNoneBlank(createStartTime)) {
            criteria.andCreateTimeGreaterThanOrEqualTo(createStartTime);
        } else if (StringUtils.isNoneBlank(createEndTime)) {
            criteria.andCreateTimeLessThanOrEqualTo(createEndTime);
        }
    }

    @Override
    public Map<String, Object> findNumberByParams(Map<String, String> params) {
        String payType = params.get("payType");
        OrderExample example = setParams(params);
        long count = orderMapper.countByExample(example);
        long totalUser = orderMapper.countCreateUserByExample(example);
        long sumTotalFee = orderMapper.sumTotalFeeByExample(example);
        Map<String, Object> map = new HashMap<>();
        if (Integer.parseInt(payType) == 3) {
            java.text.DecimalFormat df = new java.text.DecimalFormat("#.##");
            map.put("totalAmount", df.format(sumTotalFee / 100.0));
        } else {
            map.put("totalAmount", sumTotalFee);
        }
        map.put("orderCount", count);
        map.put("totalUsers", totalUser);

        return map;
    }
    public OrderExample setParams(Map<String, String> params){
        String primaryId = params.get("id");
        String payType = params.get("payType");
        String userName = params.get("userName");
        String name = params.get("name");
        String productId = params.get("productId");
        String productCode = params.get("productCode");
        String createStartTime = params.get("createStartTime");
        String createEndTime = params.get("createEndTime");
        String status = params.get("status");
        String userId = params.get("userId");
        OrderExample example = new OrderExample();
        OrderExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNoneBlank(primaryId)) {
            criteria.andIdEqualTo(Long.valueOf(primaryId));
        }
        if (!"0".equals(payType)) {
            criteria.andPayTypeEqualTo(Integer.parseInt(payType));
        }

        if (!"-1".equals(status)) {
            criteria.andStatusEqualTo(Byte.parseByte(status));
        }

        if (StringUtils.isNoneBlank(userName)) {
            if (userId != null) {
                criteria.andCreateUserEqualTo(userId);
            }
        }
        if (StringUtils.isNoneBlank(name)) {
            criteria.andNameLike("%" + name + "%");
        }
        if (StringUtils.isNoneBlank(productId)) {
            criteria.andProductIdEqualTo(Integer.parseInt(productId));
        }
        if (StringUtils.isNoneBlank(productCode)) {
            criteria.andCodeEqualTo(productCode);
        }
        addTimeRange(createStartTime, createEndTime, criteria);
        return example;
    }

}
